<?
require_once(dirname(__FILE__) . '/../../classes/module_interface.inc.php');
require_once(dirname(__FILE__) . '/../../classes/strings.inc.php');
require_once(dirname(__FILE__) . '/../../classes/browscap.inc.php');
require_once(dirname(__FILE__) . '/config.inc.php');

class LoggerModuleRobots extends LoggerStrings implements LoggerModuleInterface
{
    protected $database;
    protected $uaParser;

    public function __construct(LoggerDatabase $database) 
    {
        $this->database = $database;
        $this->stringsTable = 'module_robots_strings';
        $this->uaParser = new LoggerBrowscap();
    }

    protected function MoveToArchive($date)
    {
        $dateEscaped = '\''.mysql_escape_string($date).'\'';

        $this->database->Query('LOCK TABLES `[PREF]module_robots` WRITE, `[PREF]module_robots_archive` WRITE, `[PREF]module_robots_strings` WRITE');

        $CreateSQL = 'CREATE TEMPORARY TABLE `[PREF]module_robots_archive_temp` ( ';
        $CreateSQL .= '`date` DATE NOT NULL, ';
        $CreateSQL .= '`robot` CHAR(16) NOT NULL, ';
        $CreateSQL .= '`count` INT(10) UNSIGNED NOT NULL ';
        $CreateSQL .= ') ENGINE=MYISAM DEFAULT CHARSET=utf8 ROW_FORMAT=FIXED';
        $this->database->Query($CreateSQL);

        $ArchiveSQL = 'INSERT INTO `[PREF]module_robots_archive_temp` (`date`, `robot`, `count`) ';
        $ArchiveSQL .= 'SELECT `date`, `robot`, SUM(`count`) AS `count` FROM ( ';
        $ArchiveSQL .= 'SELECT DATE(`time`) AS `date`, `robot`, COUNT(*) AS `count` FROM `[PREF]module_robots` WHERE `time`<'.$dateEscaped.' ';
        $ArchiveSQL .= 'GROUP BY DATE(`time`), `robot` ';
        $ArchiveSQL .= 'UNION ALL ';
        $ArchiveSQL .= 'SELECT `date`, `robot`, SUM(`count`) AS `count` FROM `[PREF]module_robots_archive` ';
        $ArchiveSQL .= 'GROUP BY `date`, `robot` ';
        $ArchiveSQL .= ') `__temp_query` ';
        $ArchiveSQL .= 'GROUP BY `date`, `robot`';
        $this->database->Query($ArchiveSQL);

        $TruncateSQL = 'DELETE FROM `[PREF]module_robots_archive`';
        $this->database->Query($TruncateSQL);

        $CopySQL = 'INSERT INTO `[PREF]module_robots_archive` (`date`, `robot`, `count`) ';
        $CopySQL .= 'SELECT `date`, `robot`, `count` FROM `[PREF]module_robots_archive_temp` ';
        $this->database->Query($CopySQL);
    
        $DropSQL = 'DROP TABLE `[PREF]module_robots_archive_temp`';
        $this->database->Query($DropSQL);

        $DeleteSQL = 'DELETE FROM `[PREF]module_robots` WHERE `time`<'.$dateEscaped;
        $this->database->Query($DeleteSQL);

        $this->PurgeStrings($date);

        $this->database->Query('UNLOCK TABLES');

        return true;
    }

    public function PrepareParseSession()
    {
        if (LoggerModuleRobotsConfig::$onceInArchive)
        {
            $date = '2100-01-01';
            return $this->MoveToArchive($date);
        }
    }

    protected function DetectKnownRobot($hit)
    {
        if ($hit['source']['agent'] == '')
            return false;

        if ($hit['source']['first_for_session'])
        {
            $robotName = $this->uaParser->getRobot($hit['source']['agent']);
            if ($robotName !== false)
            {
                $session    = intval($hit['source']['session']);
                $robot = '\'' . mysql_escape_string($robotName) . '\'';
                $InsertSQL = 'INSERT INTO `[PREF]module_robots_known` (`session`, `robot`) ';
                $InsertSQL .= 'VALUES('.$session.', '.$robot.')';
                $result = $this->database->Query($InsertSQL);
                return $robotName;
            }
        }
        else
        {
            $SelectSQL = 'SELECT `robot` FROM `[PREF]module_robots_known` WHERE `session`='.intval($hit['source']['session']);
            $result = $this->database->Query($SelectSQL);
            if ($result && $row = $this->database->FetchAssoc($result))
            {
                return $row['robot'];
            }
        }

        return false;
    }

    protected function DetectUnknownRobot($hit, $pathStr)
    {
        if ($hit['source']['agent'] == '')
            return false;

        if ($hit['source']['first_for_session'])
        {
            $detected = false;
            if ($pathStr == '/robots.txt')
            {
                $detected = true;
            }
            elseif($this->uaParser->operable())
            {
                $browser = $this->uaParser->getBrowser($hit['source']['agent']);
                $platform = $this->uaParser->getPlatform($hit['source']['agent']);
                if ($browser === false && $platform === false)
                {
                    $detected = true;
                }
            }

            if ($detected)
            {
                $date       = '\'' . mysql_escape_string($hit['source']['time']) . '\'';
                $session    = intval($hit['source']['session']);
                $agent      = '\'' . mysql_escape_string($hit['source']['agent']) . '\'';
                $ip         = '\'' . mysql_escape_string($hit['source']['ip']) . '\'';
                $InsertSQL = 'INSERT INTO `[PREF]module_robots_unknown` (`date`, `session`, `agent`, `ip`) ';
                $InsertSQL .= 'VALUES('.$date.', '.$session.', '.$agent.', '.$ip.')';
                $result = $this->database->Query($InsertSQL);

                return 'Unknown';
            }
        }
        else
        {
            $SelectSQL = 'SELECT COUNT(*) AS `cnt` FROM `[PREF]module_robots_unknown` WHERE `session`='.intval($hit['source']['session']);
            $result = $this->database->Query($SelectSQL);
            if ($result && $row = $this->database->FetchAssoc($result))
            {
                if ($row['cnt'] > 0)
                    return 'Unknown';
            }
        }

        return false;
    }

    public function ParseHit(&$hit)
    {
        $parseUrlResult = $this->ParseUrl($hit['source']['url']);
        if ($parseUrlResult === false)
            return false;

        $serverStr  = $parseUrlResult['server'];
        $pathStr    = $parseUrlResult['path'];
        $queryStr   = $parseUrlResult['query'];

        if (!in_array($serverStr, LoggerConfig::$myServers))
            return false;

        $robotStr = $this->DetectKnownRobot($hit);
        if (!$robotStr)
        {
            $robotStr = $this->DetectUnknownRobot($hit, $pathStr);

            if (!$robotStr)
                return false;
        }

        $hit['modules']['robots']['robotStr']   = $robotStr;
        $hit['modules']['robots']['serverStr']  = $serverStr;
        $hit['modules']['robots']['pathStr']    = $pathStr;
        $hit['modules']['robots']['queryStr']   = $queryStr;

        $robotId    = $this->GetStringId($robotStr, $hit['source']['time']);

        $time   = '\'' . mysql_escape_string($hit['source']['time']) . '\'';
        $robot  = intval($robotId);

        if (LoggerModuleRobotsConfig::$onceInArchive)
        {
            $UpdateSQL = 'UPDATE `[PREF]module_robots_archive` SET `count`=`count`+1 ';
            $UpdateSQL .= 'WHERE `date`=DATE('.$time.') AND `robot`='.$robot;
            $result = $this->database->Query($UpdateSQL);
            if (!$result)
                trigger_error('Database Error: ' . $this->database->Error(), E_USER_ERROR);
            if ($this->database->AffectedRows() == 0)
            {
                $InsertSQL = 'INSERT INTO `[PREF]module_robots_archive` (`date`, `robot`, `count`) ';
                $InsertSQL .= 'VALUES('.$time.', '.$robot.', 1)';
                $result = $this->database->Query($InsertSQL);
                if (!$result)
                    trigger_error('Database Error: ' . $this->database->Error(), E_USER_ERROR);
            }
        }
        else
        {
            $pathId     = $this->GetStringId($pathStr, $hit['source']['time']);
            $queryId    = $this->GetStringId($queryStr, $hit['source']['time']);

            $path   = intval($pathId);
            $query  = intval($queryId);

            $InsertSQL = 'INSERT INTO `[PREF]module_robots` (`time`, `robot`, `path`, `query`) ';
            $InsertSQL .= 'VALUES('.$time.', '.$robot.', '.$path.', '.$query.')';
            $result = $this->database->Query($InsertSQL);
            if (!$result)
                trigger_error('Database Error: ' . $this->database->Error(), E_USER_ERROR);
        }
        return true;
    }

    public function Archive()
    {
        $date = LoggerModuleRobotsConfig::GetArchiveDate();
        return $this->MoveToArchive($date);
    }

    public function Purge()
    {
        $date = LoggerModuleRobotsConfig::GetPurgeDate();
        $dateEscaped = '\''.mysql_escape_string($date).'\'';

        $DeleteSQL = 'DELETE FROM `[PREF]module_robots` WHERE `time`<'.$dateEscaped;
        $this->database->Query($DeleteSQL);
        $DeleteSQL = 'DELETE FROM `[PREF]module_robots_archive` WHERE `date`<'.$dateEscaped;
        $this->database->Query($DeleteSQL);
        $DeleteSQL = 'DELETE FROM `[PREF]module_robots_unknown` WHERE `date`<'.$dateEscaped;
        $this->database->Query($DeleteSQL);
        $DeleteSQL = 'DELETE FROM `[PREF]module_robots_known` WHERE `date`<'.$dateEscaped;
        $this->database->Query($DeleteSQL);

        $OptimizeSQL = 'OPTIMIZE TABLE `[PREF]module_robots`';
        $this->database->Query($OptimizeSQL);
        $OptimizeSQL = 'OPTIMIZE TABLE `[PREF]module_robots_archive`';
        $this->database->Query($OptimizeSQL);
        $OptimizeSQL = 'OPTIMIZE TABLE `[PREF]module_robots_unknown`';
        $this->database->Query($OptimizeSQL);
        $OptimizeSQL = 'OPTIMIZE TABLE `[PREF]module_robots_known`';
        $this->database->Query($OptimizeSQL);

        $this->PurgeStrings($date);

        return true;
    }
}